package sz.com.battleship.game;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import sz.com.battleship.R;
import sz.com.battleship.game.GameElement.AiPlayer;
import sz.com.battleship.game.GameElement.Game;
import sz.com.battleship.game.GameElement.GameBoard;
import sz.com.battleship.game.adapters.gridAdapter;
import sz.com.battleship.game.adapters.shipAdapter;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class GameScreen extends Activity implements OnClickListener{
	/** Called when the activity is first created. */
	
	//layout related
	private gridAdapter adapter;
	private shipAdapter shipAdapter;
	private Button fireButton;
	private Button startButton;
	private Game theGame;
	private GridView oppoGrid;
	private GridView myGridView;
	private RelativeLayout gameLayout;
	private RelativeLayout serverLayout;
	private TextView player1Text;
	private TextView player2Text;
	private TextView waitingText;
	
	
	//currently selected position on opponents grid
	private int selectedPosition = 0;
	
	//Communication
	private Socket socket = null;
	private ServerSocket serverSocket= null;
	private String serverIpAddress = "";//"192.168.0.190";
	private int serverPort = 6000;
	private TextView ip;
	private TextView serverStatus;
	protected static final int MSG_ID = 0x1337;
	private String mClientMsg = "";
	private int positionReceive;
	private boolean server;
	private ObjectInputStream inputStream = null;
	private ObjectOutputStream outputStream = null;
	
	
	
	private boolean readyToStart = false;
	private boolean waitingForBoard = false;
	private boolean boardReceived = false;
	private Thread communicationBoardThread = null;
	private Thread communicationPositionThread = null;
	private boolean yourTurn = false;
	private boolean fired = false;
	private Handler mHandler = null;
	private boolean gameOver = false;
	
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        setContentView(R.layout.game_layout);
        gameLayout =  (RelativeLayout) findViewById (R.id.relativeLayout1);
        serverLayout = (RelativeLayout) findViewById(R.id.relativeLayout2);
        adapter = new gridAdapter(this);
        fireButton = (Button) findViewById (R.id.buttonFire);
        fireButton.setOnClickListener(this);
        startButton = (Button) findViewById (R.id.buttonStart);
        startButton.setOnClickListener(this);
        oppoGrid = (GridView) findViewById(R.id.OpponentGrid);
        oppoGrid.setAdapter(adapter);
        myGridView = (GridView) findViewById(R.id.MyOwnGrid);
        
        player1Text = (TextView) findViewById(R.id.player1Text);
        player1Text.setText("");
        player2Text = (TextView) findViewById(R.id.player2Text);
        player2Text.setText("");
        waitingText = (TextView) findViewById(R.id.waitingText);
        waitingText.setText("Waiting for other player...");
        waitingText.setVisibility(View.INVISIBLE);
        
        ip = (TextView) findViewById(R.id.serverText);
        serverStatus = (TextView) findViewById(R.id.serverStatusText);
        
        mHandler = new Handler() { //handler to modify the view from another thread
            @Override
			public void handleMessage(Message msg) {
				// TODO Auto-generated method stub
            	int position = (Integer) msg.obj;
            	if(position == -1){
            		startButton.setVisibility(View.VISIBLE);
            		waitingText.setVisibility(View.GONE);
            	}
            	else{
            		displayAttackState(2,position);
            	}
			}
        };
        
        initGame();
    }
    
    


	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		try {
			gameOver = true;
			readyToStart = true;
			if(server && serverSocket!= null)
				serverSocket.close();
			if(socket != null)
				socket.close();
        	if(inputStream != null)
        		inputStream.close();
        	if(outputStream != null)
        		outputStream.close();
        	
        } catch (IOException e) {
                e.printStackTrace();
        }
	}

	private void initGame(){
		gameLayout.setVisibility(View.INVISIBLE);
		
		if(!GameMenu.singlePlayer){   //multiplayer
			startButton.setVisibility(View.GONE);
			serverLayout.setVisibility(View.VISIBLE);
	        Bundle extras = getIntent().getExtras();
	        if (extras !=null)
	        {
	        	
	        	if (extras.getBoolean("Server"))
	        	{
	        		serverIpAddress = extras.getString("IP");
	        		ip.setText("The IP of the Server is: " + serverIpAddress + " Port: " + serverPort);
	        		serverStatus.setText("Waiting for client to connect...");
	        		Thread cThread = new Thread(new ServerConnectThread());
	                cThread.start();
	                server = true;
	        	}
	        	else
	        	{
	        		serverLayout.setVisibility(View.GONE);
	        		serverIpAddress = extras.getString("IP");
	        		serverPort = extras.getInt("PORT");
	        		Thread cThread = new Thread(new ClientConnectThread());
	                cThread.start();
	                server = false;
	        	}
	        	
	        }
			
		}
		else{
			serverLayout.setVisibility(View.INVISIBLE);
			startShipPlacement();
		}
    }
    private void startGame() {
		startButton.setVisibility(View.GONE);
		gameLayout.setVisibility(View.VISIBLE);
    	if(GameMenu.singlePlayer){	
    		//Single player mode
    		AiPlayer player2 = (AiPlayer)theGame.getPlayer2();	
    		if(theGame.isStart()){
    			player1Text.setText("You start!");
    		}
    		else{
    			player1Text.setText("Player 2 start!");
    			displayAttackState(2, player2.getShot());
    		}
		}
		else{
			//Multiplayer mode
			if(readyToStart){
				communicationBoardThread = null;
				if(theGame.getStart()){
					yourTurn = true;
					player1Text.setText("You Start!");
				}
				else{
					player2Text.setText("Wait for other player to start");
				}
				communicationPositionThread= new Thread(new CommunicationPosition());
				communicationPositionThread.start();
			}

    	}
	}
    //result from the ship placement activity
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {		
		if (resultCode == 0) {
			finish();
		} 
		else {
			theGame = new Game(GameMenu.singlePlayer);
			theGame.getPlayer1().setGameBoard((GameBoard)data.getSerializableExtra("GameBoard"));
			shipAdapter = new shipAdapter(this,(GameBoard)data.getSerializableExtra("GameBoard"));
			myGridView.setAdapter(shipAdapter);
			oppoGrid.setOnItemClickListener(new OnItemClickListener() {
	            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
	            	selectedPosition = position;
	            }
			});
			if(!GameMenu.singlePlayer)
			{
				communicationBoardThread = new Thread(new CommunicationBoard());
				communicationBoardThread.start();
				waitingText.setVisibility(View.VISIBLE);
			}
		}
	}
	private void startShipPlacement(){
		Intent myIntent = new Intent(this,ShipPlacementScreen.class);
    	startActivityForResult(myIntent,1);
	}
	public void onClick(View v) {
		// TODO Auto-generated method stub
		if(v.getId() == R.id.buttonFire)
		{
			if(GameMenu.singlePlayer){
				if(displayAttackState(1, this.selectedPosition) != -1){
					displayAttackState(2, ((AiPlayer)theGame.getPlayer2()).getShot());
				}
			}
			else{
				if(yourTurn){
					if(displayAttackState(1, this.selectedPosition)!=-1){
						fired = true;
					}
				}
			}
		}
		else if(v.getId() == R.id.buttonStart){

	        startGame();
		}
	}
	//Display of the attack state on the game board on screen
	private int displayAttackState(int playerNumber, int positionHit){
		
		if(playerNumber == 1){
			int attackState = theGame.getPlayer2().getGameBoard().receiveFire(positionHit);
			ImageView view = (ImageView) oppoGrid.getChildAt(positionHit);
			switch(attackState)
			{
			case -1:
				player1Text.setText("You have already fired at at this location!");
				break;
			case 0:
				player1Text.setText("You missed!");
				view.setImageResource((Integer) adapter.getMiss());
				break;
			case 1:
				player1Text.setText("Hit on target!");
				view.setImageResource((Integer) adapter.getCrash());
				break;
			case 2:
				player1Text.setText("Hit on target, sinked!");
				view.setImageResource((Integer) adapter.getCrash());
				break;
			case 3:
				player1Text.setText("Sinked! YOU WON!");
				view.setImageResource((Integer) adapter.getCrash());
				AlertDialog wonDialog = new AlertDialog.Builder(this).create();
				wonDialog.setMessage("Congratulation, you're the winner!");
				wonDialog.setButton("OK", new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						setResult(RESULT_OK);
						if(!GameMenu.singlePlayer){
							communicationPositionThread = null;
							gameOver = true;
						}
						finish();
					}
				});
				wonDialog.setCanceledOnTouchOutside(false);
				wonDialog.show();
			}
			return attackState;
		}
		else{
			int attackState = theGame.getPlayer1().getGameBoard().receiveFire(positionHit);
			ImageView view = (ImageView) myGridView.getChildAt(positionHit);
			switch(attackState)
			{
			case 0:
				player2Text.setText("He missed!");
				if(!GameMenu.singlePlayer)
					player1Text.setText("Your turn!");
				view.setImageResource((Integer) adapter.getMiss());
				break;
			case 1:
				player2Text.setText("Hit on target!");
				if(!GameMenu.singlePlayer)
					player1Text.setText("Your turn!");
				view.setImageResource((Integer) adapter.getCrash());
				break;
			case 2:
				player2Text.setText("Hit on target, sinked!");
				if(!GameMenu.singlePlayer)
					player1Text.setText("Your turn!");
				view.setImageResource((Integer) adapter.getCrash());
				break;
			case 3:
				player2Text.setText("Sinked! YOU LOST!");
				view.setImageResource((Integer) adapter.getCrash());
				AlertDialog wonDialog = new AlertDialog.Builder(this).create();
				wonDialog.setMessage("Sorry, you lost!");
				wonDialog.setButton("OK", new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						setResult(RESULT_OK);
						if(!GameMenu.singlePlayer){
							communicationPositionThread = null;
							gameOver = true;
						}
						finish();
					}
				});
				wonDialog.setCanceledOnTouchOutside(false);
				wonDialog.show();
			}
			return attackState;
		}
	}
	Handler myUpdateHandler = new Handler() {
        public void handleMessage(Message msg) {
                switch (msg.what) {
                case MSG_ID:
                        TextView tv = (TextView) findViewById(R.id.serverStatusText);
                        tv.setText(mClientMsg);
                        serverLayout.setVisibility(View.GONE);
                        startShipPlacement();
                        
                        break;
                default:
                        break;
                }
                super.handleMessage(msg);
        }
	};
	//Thread to connect for the Server
	class ServerConnectThread implements Runnable {
        public void run() {                
            try {
            	serverSocket = new ServerSocket(serverPort);

            	Log.d("GameScreen", "Server: Avant Accept");
            	if (socket == null)
                    socket = serverSocket.accept();
            	socket.setKeepAlive(true);
            	outputStream = new ObjectOutputStream(socket.getOutputStream());
            	outputStream.flush();
            	inputStream = new ObjectInputStream(socket.getInputStream());

            	 Message m = new Message();
                 m.what = MSG_ID;
                 mClientMsg = "Connected";
                 myUpdateHandler.sendMessage(m);
            	
            } catch (IOException e) {
                    e.printStackTrace();
            }
        }
    }
	//Thread to connect for the Client
	class ClientConnectThread implements Runnable {
        public void run() {                
            try {
            	
            	Log.d("GameScreen", "Client before connected");
            	InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
            	socket = new Socket(serverAddr, serverPort);
            	socket.setKeepAlive(true);
            	outputStream = new ObjectOutputStream(socket.getOutputStream());
            	outputStream.flush();
            	inputStream = new ObjectInputStream(socket.getInputStream());

             	Log.d("GameScreen", "Client conntected");
             	startShipPlacement();
            	
            } catch (IOException e) {
                    e.printStackTrace();
                    finish();
            }
        }
    }
	//Communication of positions
	class CommunicationPosition implements Runnable {
        public void run() {   
        	//Connection establish
        	while (socket!=null && !gameOver)
        	{
        		if (yourTurn && fired)
        		{
        			Log.d("GameScreen", "Send to shot :" + selectedPosition);
        			try {
						outputStream.writeObject((Integer)selectedPosition);
						yourTurn = false;
	        			fired = false;
					} catch (IOException e) {
						e.printStackTrace();
					}        			
        		}
        		else if(!yourTurn)
        		{   	
					try {
						Log.d("GameScreen", "Before Read position");
						positionReceive = (Integer)inputStream.readObject();
	    				Message msg = new Message();
	    		        msg.obj = positionReceive;
	    		        mHandler.sendMessage(msg);
	    				yourTurn = true;
						Log.d("GameScreen", "After Read position :" + positionReceive );
					} catch (OptionalDataException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (ClassNotFoundException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
        		}
        	}
        	finish();
        }
    }	
	//Communication of the Board and who starts
	class CommunicationBoard implements Runnable {
        public void run() {   
        	while (socket!=null && !readyToStart)
        	{
        		if(server){
	    			try{
	    				Log.d("Server", "writeObject11");
	    				outputStream.writeObject(theGame.getPlayer1().getGameBoard());
	    				outputStream.reset();
	    				outputStream.writeObject(!theGame.isStart());
	    				waitingForBoard = true;
	    			}catch(IOException e)
	    			{
	    				e.printStackTrace();
	    			}
	    			if(waitingForBoard){

    					try 
    					{
    						Log.d("Server", "readObject");
							theGame.getPlayer2().setGameBoard((GameBoard)inputStream.readObject());
							Log.d("Server", "gameBoardSET");
		    				readyToStart = true;
							Message msg = new Message();
		    		        msg.obj = -1;
		    		        mHandler.sendMessage(msg);
		    				
						} catch (IOException e) {
							e.printStackTrace();
						} catch (ClassNotFoundException e) {
							e.printStackTrace();
						}
    				}
        		}
        		else{ //Client
        			try 
					{
						theGame.getPlayer2().setGameBoard((GameBoard)inputStream.readObject());
						theGame.setStart((Boolean)inputStream.readObject());
						boardReceived = true;
						Log.d("Client", "gameBoardSET");
					} catch (IOException e) {
						e.printStackTrace();
					} catch (ClassNotFoundException e) {
						e.printStackTrace();
					}
        			if(boardReceived){
	        			try{
		    				outputStream.writeObject(theGame.getPlayer1().getGameBoard());
		    				readyToStart = true;
    						Message msg = new Message();
    	    		        msg.obj = -1;
    	    		        mHandler.sendMessage(msg);
		    				
		    			}catch(IOException e)
		    			{
		    				e.printStackTrace();
		    			}
        			}
        		}  		
        	}
        }
	}
}
